//
// Created by feng on 19-4-17.
//

#include <cmath>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numbers>
#include <sstream>


#include <boost/gil.hpp>
#include <boost/gil/extension/io/png.hpp>
#include <boost/gil/image.hpp>
#include <boost/gil/image_view.hpp>
#include <boost/gil/io/io.hpp>
#include <boost/gil/typedefs.hpp>

#include "ImageSaver.h"
#include <algorithm/rayTracing/qmcrt_util/global_constant.h>
#include <utils/Format.h>
#include <utils/Print.h>


using namespace std;
using namespace boost::gil;
using namespace solar;

ColorBar ImageSaver::colorbar;

/**
 * 通过结果数组生成flux map
 *      boost::gil
 *      colorbar----自定义
 */
void ImageSaver::saveImg(const std::string& file_path, int height, int width, float* data,
                         float max_val)
{
    solar::println("======================= ImageSaver:save image==================");
    colorbar.setMinMax(0.0, max_val);
    // ColorBar colorbar(0, max_val);
    // colorbar.test();
    // colorbar
    // std::cout <<"111\n";

    std::cout << "height=" << height << "  width=" << width << std::endl;
    // for(int i=0;i<height;i++)
    // {
    //     for(int j=0;j<width;j++)
    //     {
    //         int id = i*width + j;
    //         std::cout <<data[id] <<" ";
    //     }
    //     std::cout <<std::endl;
    // }

    boost::gil::rgb8_image_t img(width, height);
    auto img_view = view(img);
    rgb8_pixel_t pixel;
    // std::cout <<"222\n";
    if (!data)
    {
        solar::println("error::data is nullptr");
    }
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            int current_index = i * width + j;
            float current_flux = data[current_index];
            pixel = colorbar.getColorAtValue(current_flux);

            img_view(j, i) = pixel;
        }
    }
    write_view(file_path, img_view, png_tag());
}

auto ImageSaver::saveText(int receiver_type, const std::string& paths, int height, int width,
                          float* h_data, float receiver_pixel, int time, bool res, float& sum_power,
                          float& maximum_flux, int& maximum_location_x, int& maximum_location_y,
                          int precision, int rows_package) -> float
{
    std::string filename;

    int rece = receiver_type;
    string names = to_string(rece);
    if (res)
    {
        filename = paths + "refract" + names + ".txt";
    }
    else
    {
        filename = paths + "reflect" + names + ".txt";
    }
    solar::println(solar::format("filename = {}", filename));
    // 0 is rect
    // 1 is cylinder
    // 2 is refind rect
    // 3 is refind cylinder
    // 4 is multipanel
    float h = receiver_pixel;
    float rece_pixel = 0;
    int tube_unit = 20;
    float theta = std::numbers::pi / tube_unit;
    float r1 = 0.01105;
    float l = 0;
    int panel = 18;
    int tube = 62;
    float rece_R = 4.25;

    rece = 1;
    switch (rece)
    {
    case 0:
        rece_pixel = h * h;
        break;
    case 1:
        rece_pixel = h * h;

        break;
    case 2:
        rece_pixel = h * h;
        break;
    case 3:
        l = theta * r1;
        rece_pixel = h * l;
        printf("l %f  %d %d\n", l, height, width);
        break;
    case 4:
        l = rece_R * sin(std::numbers::pi / panel) / tube;
        rece_pixel = h * l;
        printf("save h %f l %f  \n", h, l);
        break;
    default:
        receiver_pixel = h * h;
        break;
    }

    std::ofstream fout(filename.c_str());
    std::stringstream ss;
    int address = 0;
    float max_value = 0.0f;
    float summation_value = 0.0f;
    float x, y;
    float t = receiver_pixel;
    float abs = 0.0f;

    int max_value_located_row_index, max_value_located_col_index;

    for (int r = 0; r < height; ++r)
    {
        if (r % rows_package == rows_package - 1)
        {
            fout << ss.rdbuf();
            ss.clear();
        }

        for (int c = 0; c < width; ++c)
        { // 倒过来存储的 txt 0行是接收器顶部 最后一行是接收器底部
            address = (height - 1 - r) * width + c;
            float val = h_data[address] / (static_cast<float>(time));
            if (val < Epsilon)
            {
                ss << 0;
            }
            else
            {
                max_value = std::max(max_value, val);
                if (max_value == h_data[address])
                {
                    max_value_located_row_index = r;
                    max_value_located_col_index = c;
                }

                summation_value += val * rece_pixel;
                ss << std::fixed << std::setprecision(precision) << val;
            }

            if (c != width - 1)
            {
                ss << " ";
            }
            else
            {
                ss << '\n';
            }
        }
    }
    solar::println(solar::format("max value is {} KW/m2", max_value / 1000));
    solar::println(solar::format("sum value is {} KW", summation_value / 1000));
    solar::println(solar::format("max location: ({}, {})", max_value_located_row_index,
                                 max_value_located_col_index));
    // std::cout << ". Sumabs value is " << abs << "kw." << std::endl;

    maximum_flux = max_value / 1000;
    sum_power = summation_value / 1000;
    maximum_location_x = max_value_located_col_index;
    maximum_location_y = max_value_located_row_index;

    fout << ss.rdbuf();
    fout.close();

    std::string res_name;
    if (res)
    {
        res_name = paths + "refract_maxs.txt";
    }
    else
    {
        res_name = paths + "reflect_maxs.txt";
    }
    std::ofstream fout_1(res_name.c_str(), std::ios::app);
    fout_1 << max_value << std::endl;

    fout_1.close();
    std::string res_name_2;
    if (res)
    {
        res_name_2 = paths + "refract_sums.txt";
    }
    else
    {
        res_name_2 = paths + "reflect_sums.txt";
    }
    std::ofstream fout_2(res_name_2.c_str(), std::ios::app);

    fout_2 << summation_value << std::endl;

    fout_2.close();

    return summation_value;
}

void ImageSaver::saveCSV(const std::string& filename, int height, int width, float* h_data,
                         float receiver_pixel, bool res, int time)
{
    std::string new_filename;
    if (res)
    {
        new_filename = filename + "refract.csv";
    }
    else
    {
        new_filename = filename + "reflect.csv";
    }

    std::ofstream fout(filename.c_str());
    std::stringstream ss;
    fout << 'x' << ',' << 'y' << ',' << "flux(W/m2)" << std::endl; // hieght=8,width=10
    int address = 0;
    float max_value = 0.0f;
    float summation_value = 0.0f;
    float x, y;
    float t = receiver_pixel;
    float abs = 0.0f;

    for (int r = 0; r < height; ++r)
    {
        //  printf("r=%d\n",r);
        for (int c = 0; c < width; ++c)
        {
            y = (2 * r + 1) * t / 2;
            x = width * t - (2 * c + 1) * t / 2;

            address = (height - 1 - r) * width + c;
            float val = h_data[address] / (static_cast<float>(time));

            if (val < Epsilon * 0.1)
            {
                fout << x << ',' << y << ',' << 0 << std::endl;
            }
            else
            {
                max_value = std::max(max_value, val);
                summation_value += val * t * t;
                abs += val * t * t;
                fout << x << ',' << y << ',' << val << std::endl;
            }
        }
    }
    fout << ss.rdbuf();
    fout.close();
}
